#pragma once

#include <string>
#include <vector>

namespace Thinder
{
namespace ParseTree
{

using std::string;
using std::vector;

struct Thinder;
struct Declaration;
struct Type;
struct Identifier;

typedef vector<Identifier> Name;

#include "parsetree_statement.h"
#include "parsetree_expression.h"

struct Thinder
{
    Name ns;
    vector<Name> imports;
    vector<Declaration> declarations;
};

struct Identifier 
{
    Identifier();
    Identifier(string ident);
    string identifier;
    int ch;
    int line;
    int col;
    
    bool operator<(const Identifier &other) const;
    bool operator==(const Identifier &other) const;
    bool operator!=(const Identifier &other) const;
};

struct Type
{
    enum TypeType { PrimitiveType, UserType };
    enum Primitive { Int, Float, Bool, Char, Byte, Short, Long, Double }; // TODO void
    TypeType typeType;
    vector<Expression> arrayExpr;
    Primitive primitiveType;
    Name userType;
    
    bool operator==(const Type &other) const;
    bool operator!=(const Type &other) const;
    
    static Type Unknown();
};

enum Modifier { Public, Protected, Private, Static, Abstract, Final };

struct Var 
{
    Identifier identifier;
    bool init;
    Expression expression;
};

struct FormPar 
{
    Type type;
    Identifier identifier;
};

struct ClassDeclaration
{
    enum DeclType { FieldMeth, Constructor };
    DeclType declType;
    
    // declaration attributes
    Declaration *declaration;
    
    // constructor
    vector<Modifier> modifiers;
    Identifier identifier;
    vector<FormPar> formPars;
    Statement statement;
};

struct Declaration
{
    enum DeclType { VarDecl, FunctionDecl, OperatorDecl, ClassDecl };
    DeclType declType;
    Type type;
    vector<Modifier> modifiers;
    Identifier identifier;
    
    // function attributes
    vector<FormPar> formPars;
    Statement statement;
    
    // var attributes
    vector<Var> vars;
    
    // class attributes;
    vector<Name> extends;
    vector<ClassDeclaration> classdecls;
};

} // namespace ParseTree
} // namespace Thinder

